package longshu.data.common.mybatis;

import lombok.extern.slf4j.Slf4j;
import longshu.data.common.ds.DynamicDataSource;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.TransactionIsolationLevel;

import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;

/**
 * DynamicSqlSessionFactory 动态SqlSessionFactory(单例)
 * <p>动态Mapper的关键是动态的SqlSessionFactory产生动态的SqlSession</p>
 *
 * @author xuhailong3 2018/01/20
 * @see longshu.data.common.ds.DynamicDataSource
 * @see org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
 */
@Slf4j
public class DynamicSqlSessionFactory implements SqlSessionFactory {

    protected Map<Object, SqlSessionFactory> sqlSessionFactorys = new HashMap<>(4);

    protected SqlSessionFactory defaultSqlSessionFactory;

    private static final DynamicSqlSessionFactory INSTANCE = new DynamicSqlSessionFactory();

    private DynamicSqlSessionFactory() {
    }

    public static DynamicSqlSessionFactory getInstance() {
        return INSTANCE;
    }

    public SqlSessionFactory addSqlSessionFactory(Object dataSource, SqlSessionFactory sessionFactory) {
        log.debug("dataSource:{}, sessionFactory:{}", dataSource, sessionFactory);
        return sqlSessionFactorys.put(dataSource, sessionFactory);
    }

    public void setSqlSessionFactorys(Map<Object, SqlSessionFactory> sqlSessionFactorys) {
        this.sqlSessionFactorys.putAll(sqlSessionFactorys);
    }

    public void setDefaultSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        this.defaultSqlSessionFactory = sqlSessionFactory;
    }

    /**
     * @see DynamicDataSource#determineCurrentLookupKey()
     */
    public SqlSessionFactory getSqlSessionFactory() {
        Object key = DynamicDataSource.getInstance().determineCurrentLookupKey();
        log.debug("key:{}", key);
        SqlSessionFactory sessionFactory = sqlSessionFactorys.get(key);
        if (null == sessionFactory) {
            sessionFactory = defaultSqlSessionFactory;
        }
        return sessionFactory;
    }

    /*
     * SqlSessionFactory
     */

    @Override
    public SqlSession openSession() {
        return getSqlSessionFactory().openSession();
    }

    @Override
    public SqlSession openSession(boolean autoCommit) {
        return getSqlSessionFactory().openSession(autoCommit);
    }

    @Override
    public SqlSession openSession(Connection connection) {
        return getSqlSessionFactory().openSession(connection);
    }

    @Override
    public SqlSession openSession(TransactionIsolationLevel level) {
        return getSqlSessionFactory().openSession(level);
    }

    @Override
    public SqlSession openSession(ExecutorType execType) {
        return getSqlSessionFactory().openSession(execType);
    }

    @Override
    public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
        return getSqlSessionFactory().openSession(execType, autoCommit);
    }

    @Override
    public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
        return getSqlSessionFactory().openSession(execType, level);
    }

    @Override
    public SqlSession openSession(ExecutorType execType, Connection connection) {
        return getSqlSessionFactory().openSession(execType, connection);
    }

    @Override
    public Configuration getConfiguration() {
        return getSqlSessionFactory().getConfiguration();
    }

}
